package cn.xydata.es;

import cn.xydata.common.dto.ParamsDto;
import cn.xydata.common.dto.ResponsePageDto;
import cn.xydata.common.util.DateUtils;
import cn.xydata.common.util.IdGenerator;
import cn.xydata.common.util.JsonUtil;
import cn.xydata.constant.enums.TaxProjectEnum;
import cn.xydata.dto.company.company.QueryCompanyPageSearchObjectDto;
import cn.xydata.dto.tax.comprehensive.QueryComprehensivePageSearchObjectDto;
import cn.xydata.dto.tax.payment.TaxPaymentSearchObjectDto;
import cn.xydata.utils.PageUtil;
import cn.xydata.vo.company.company.QueryCompanyPageDataVo;
import cn.xydata.vo.tax.comprehensive.QueryComprehensivePageDataVo;
import cn.xydata.vo.tax.payment.TaxPaymentDataVo;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.*;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.analysis.Analyzer;
import co.elastic.clients.elasticsearch._types.analysis.PatternAnalyzer;
import co.elastic.clients.elasticsearch._types.mapping.DynamicTemplate;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.UpdateByQueryResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.elasticsearch.indices.IndexSettingsAnalysis;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.Year;
import java.util.*;
import java.util.stream.Collectors;

import static cn.xydata.es.EsUtil.cardinalityAggregation;
import static cn.xydata.es.EsUtil.sumAggregation;

/**
 * @author tz
 * @create 2024-02-26
 */
public class NewEsTest {

    private static HttpHost[] toHttpHost() {
        if (!org.springframework.util.StringUtils.hasLength("172.16.1.232:9200")) {
            throw new RuntimeException("invalid elasticsearch configuration. elasticsearch.hosts不能为空！");
        }

        // 多个IP逗号隔开
        String[] hostArray = "172.16.1.232:9200".split(",");
        HttpHost[] httpHosts = new HttpHost[hostArray.length];
        HttpHost httpHost;
        for (int i = 0; i < hostArray.length; i++) {
            String[] strings = hostArray[i].split(":");
            httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");
            httpHosts[i] = httpHost;
        }

        return httpHosts;
    }

    public static ElasticsearchClient elasticsearchClient() {
        HttpHost[] httpHosts = toHttpHost();
        // Create the RestClient
        RestClient restClient = RestClient.builder(httpHosts).build();
        // Create the transport with a Jackson mapper
        RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        // create the API client
        return new ElasticsearchClient(transport);
    }

    private static void test4(ElasticsearchClient esClient) throws IOException {
        Map<String, Property> propertyMap = new HashMap<>();

        propertyMap.put("companyName", Property.of(builder -> builder.text(builder1 -> builder1.analyzer("ik_max_word"))));
        propertyMap.put("tax_test", Property.of(builder -> builder.double_(builder1 -> builder1)));
        propertyMap.put("tax_test2", Property.of(builder -> builder.double_(builder1 -> builder1)));

        IndexSettings.Builder settingBuilder = new IndexSettings.Builder();

        Map<String, DynamicTemplate> dynamicTemplateMap = new HashMap<>();
        Property pointProperty = new Property.Builder().scaledFloat(builder -> builder.scalingFactor(100.0)).build();
        DynamicTemplate dynamicTemplate = new DynamicTemplate.Builder().matchMappingType("double").mapping(pointProperty).build();
        dynamicTemplateMap.put("my_point_number", dynamicTemplate);

        esClient.indices().create(c -> c.index("company_tax_test6").settings(builder -> builder).mappings(builder -> builder
                .dynamicTemplates(dynamicTemplateMap)));

        CompanyTax companyTax = new CompanyTax();
        companyTax.setConsumeTax(new BigDecimal("1662.33"));
        companyTax.setEstablishDate(new Date());

        esClient.index(idx -> idx
                .index("company_tax_test6")
                .id(IdGenerator.getNextId())
                .document(companyTax));
    }

    public static void main(String[] args) throws Exception {

        ElasticsearchClient esClient = elasticsearchClient();
        testCompanyCreate(esClient);
        testTaxPaymentCreate(esClient);
    }

    private static ResponsePageDto<QueryCompanyPageDataVo> companyTest(ElasticsearchClient esClient, ParamsDto<QueryCompanyPageSearchObjectDto> paramsDto) throws IOException {
        QueryCompanyPageSearchObjectDto searchObject = paramsDto.getSearchObject(QueryCompanyPageSearchObjectDto.class);
        List<Query> queryList = new ArrayList<>();
        //企业模糊查找
        if (StringUtils.isNotBlank(searchObject.getCompanyName())) {
            if (searchObject.getCompanyName().contains("*")) {
                searchObject.setCompanyName(searchObject.getCompanyName().replace("*", "\\*"));
            }
            queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*" + searchObject.getCompanyName() + "*"));
        }
        //联系人模糊查找
        if (StringUtils.isNotBlank(searchObject.getContactPersonName())) {
            queryList.add(EsUtil.wildcardQuery("contactPersonName.keyword", "*" + searchObject.getContactPersonName() + "*"));
        }
        //经营地址模糊查找
        if (StringUtils.isNotBlank(searchObject.getOperatingAddress())) {
            queryList.add(EsUtil.wildcardQuery("operatingAddress.keyword", "*" + searchObject.getOperatingAddress() + "*"));
        }
        //财政行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getFinanceName())) {
            queryList.add(EsUtil.matchQuery("financeIndustryId", String.join(",", searchObject.getFinanceName())));
        }
        //财政行业匹配
        if (!CollectionUtils.isEmpty(searchObject.getPartName())) {
            String nowYear = DateUtils.format(new Date(), DateUtils.TimeFormat.PURE_YEAR);
            queryList.add(EsUtil.matchQuery("financePartId." + nowYear, String.join(",", searchObject.getPartName())));
        }
        //工商行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getBusinessName())) {
            queryList.add(EsUtil.matchQuery("businessIndustryId", String.join(",", searchObject.getBusinessName())));
        }
        //税务行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getTaxName())) {
            queryList.add(EsUtil.matchQuery("taxIndustryId", String.join(",", searchObject.getTaxName())));
        }
        //集团匹配
        if (!CollectionUtils.isEmpty(searchObject.getGroupName())) {
            queryList.add(EsUtil.matchQuery("groupId", String.join(",", searchObject.getGroupName())));
        }
        BoolQuery boolQuery = new BoolQuery.Builder().must(queryList).build();
        Query queryBool = new Query.Builder().bool(boolQuery).build();

        SearchResponse<Company> search = esClient.search(builder -> builder
                .index("financial_index_company")
                .query(queryBool)
                .from(paramsDto.getCurrent())
                .size(paramsDto.getPageSize())
                .sort(EsUtil.sortOptions("companyName.keyword", false)), Company.class);

        List<Company> collect = search.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
        PageInfo<Company> pageInfo = new PageInfo<>(collect);
        List<QueryCompanyPageDataVo> res = collect.stream().map(QueryCompanyPageDataVo::new).collect(Collectors.toList());
        return PageUtil.getResponsePageDto(pageInfo, res);
    }

    private static ResponsePageDto<QueryComprehensivePageDataVo> comprehensiveTest(ElasticsearchClient esClient, ParamsDto<QueryComprehensivePageSearchObjectDto> paramsDto) throws IOException {
        long from = (long) (paramsDto.getCurrent() - 1) * paramsDto.getPageSize();
        long to = (long) paramsDto.getCurrent() * paramsDto.getPageSize();
        QueryComprehensivePageSearchObjectDto searchObject = paramsDto.getSearchObject(QueryComprehensivePageSearchObjectDto.class);

        //搜索条件
        List<Query> queryList = new ArrayList<>();
        //企业模糊查找
        if (StringUtils.isNotBlank(searchObject.getCompanyName())) {
            if (searchObject.getCompanyName().contains("*")) {
                searchObject.setCompanyName(searchObject.getCompanyName().replace("*", "\\*"));
            }
            queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*" + searchObject.getCompanyName() + "*"));
        }
        //集团精确匹配
        if (StringUtils.isNotBlank(searchObject.getGroupId())) {
            queryList.add(EsUtil.termQuery("groupId", searchObject.getGroupId()));
        }
        //年份查询
        if (searchObject.getTaxYear() == null) {
            searchObject.setTaxYear(LocalDate.now().getYear());
        }
        queryList.add(EsUtil.termQuery("taxYear", searchObject.getTaxYear().toString()));
        //搜索条件封装
        Query queryBool = EsUtil.boolQuery(queryList);

        //总数据量
        String totalAggregationName = "total";
        SearchResponse<CompanyTax> totalSearch = esClient.search(builder -> builder
                        .index("financial_index_company_tax")
                        .query(queryBool)
                        .aggregations(totalAggregationName,  EsUtil.cardinalityAggregation("companyId.keyword"))
                        , CompanyTax.class);
        long total = (long) totalSearch.aggregations().get(totalAggregationName).cardinality().value();
        if (to > total || to >= 5000L) {
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        //terms聚合
        HashMap<String, SortOrder> orderMap = new HashMap<>();
        if (searchObject.getOrderWay().equals("taxAmount")) {
            orderMap.put("taxAmount", SortOrder.Asc);
        } else {
            orderMap.put("taxAmount", SortOrder.Desc);
        }
        List<Map<String, SortOrder>> orderList = new ArrayList<>();
        orderList.add(orderMap);
        TermsAggregation termsAggregation = new TermsAggregation.Builder().field("companyId.keyword")
                .order(orderList).size((int)to).build();

        //sum嵌套脚本索引
        List<String> docList = new ArrayList<>();
        for (TaxProjectEnum taxProjectEnum : TaxProjectEnum.values()) {
            if (taxProjectEnum.equals(TaxProjectEnum.environmentalProtectionTax)) {
                continue;
            }
            docList.add(taxProjectEnum.name());
        }
        SumAggregation sumAggregation = new SumAggregation.Builder().script(EsUtil.sumInlineScript(docList)).build();
        Aggregation totalAmountAggregation = new Aggregation.Builder().sum(sumAggregation).build();

        //聚合整合
        String aggregationName = "companyTax";
        Aggregation aggregation = new Aggregation.Builder().terms(termsAggregation)
                        .aggregations("taxAmount", totalAmountAggregation)
                        .aggregations("companyInfo", EsUtil.topHitsAggregation((int) 1))
                        .build();
        //查询数据
        SearchResponse<CompanyTax> search = esClient.search(builder -> builder
                .index("financial_index_company_tax")
                .query(queryBool)
                .size(0)
                .aggregations(aggregationName, aggregation)
                , CompanyTax.class);
        //数据整理
        List<QueryComprehensivePageDataVo> res = new ArrayList<>();
        Aggregate companyTaxAggregate = search.aggregations().get(aggregationName);
        List<StringTermsBucket> bucketList = companyTaxAggregate.sterms().buckets().array();
        for (int i = (int)from; i < (int)to; i++) {
            StringTermsBucket bucket = bucketList.get(i);
            Map<String, Aggregate> collect = bucket.aggregations().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            CompanyTax companyTax = collect.get("companyInfo").topHits().hits().hits().stream().map(Hit::source).collect(Collectors.toList()).get(0).to(CompanyTax.class);
            double taxAmountValue = collect.get("taxAmount").sum().value();
            BigDecimal taxAmount = BigDecimal.valueOf(taxAmountValue).setScale(2, RoundingMode.HALF_UP);
            QueryComprehensivePageDataVo tmp = new QueryComprehensivePageDataVo(companyTax, taxAmount);
            res.add(tmp);
        }
        PageInfo<QueryComprehensivePageDataVo> pageInfo = new PageInfo<>(res);
        ResponsePageDto<QueryComprehensivePageDataVo> responsePageDto = PageUtil.getResponsePageDto(pageInfo);
        responsePageDto.setTotal(total);
        responsePageDto.setFirst(paramsDto.getCurrent() == 1);
        responsePageDto.setIsLast(to == total);
        return responsePageDto;
    }

    private static ResponsePageDto<TaxPaymentDataVo> taxPaymentTest(ElasticsearchClient esClient, ParamsDto<TaxPaymentSearchObjectDto> paramsDto) throws Exception {
        long from = (long) (paramsDto.getCurrent() - 1) * paramsDto.getPageSize();
        long to = (long) paramsDto.getCurrent() * paramsDto.getPageSize();
        TaxPaymentSearchObjectDto searchObject = paramsDto.getSearchObject(TaxPaymentSearchObjectDto.class);

        Query taxPaymentQuery = getTaxPaymentQuery(searchObject);

        //总数据量
        String totalAggregationName = "total";
        SearchResponse<CompanyTax> totalSearch = esClient.search(builder -> builder
                        .index("financial_index_company_tax")
                        .query(taxPaymentQuery)
                        .aggregations(totalAggregationName,  EsUtil.cardinalityAggregation("companyId.keyword"))
                , CompanyTax.class);
        long total = (long) totalSearch.aggregations().get(totalAggregationName).cardinality().value();
        if (to > total || to >= 5000L) {
            return PageUtil.getBlankResponsePage(paramsDto);
        }

        //term聚合
        List<Map<String, SortOrder>> orderList = new ArrayList<>();
        HashMap<String, SortOrder> orderMap = new HashMap<>();
        orderMap.put("taxYear", SortOrder.Desc);
        orderList.add(orderMap);
        orderMap = new HashMap<>();
        if (null != searchObject.getOrderWay()) {
            switch (searchObject.getOrderWay()) {
                case "totalAmount": {
                    orderMap.put("totalAmount", SortOrder.Asc);
                    break;
                }
                case "taxTotalAmount": {
                    orderMap.put("taxTotalAmount", SortOrder.Asc);
                    break;
                }
                case "unTaxTotalAmount": {
                    orderMap.put("unTaxTotalAmount", SortOrder.Asc);
                    break;
                }
                case "offsetTotal": {
                    orderMap.put("offsetTotal", SortOrder.Asc);
                    break;
                }
                case "valueAddedTaxSubtotal": {
                    orderMap.put("valueAddedTaxSubtotal", SortOrder.Asc);
                    break;
                }
                case "totalAmount_desc": {
                    orderMap.put("totalAmount", SortOrder.Desc);
                    break;
                }
                case "taxTotalAmount_desc": {
                    orderMap.put("taxTotalAmount", SortOrder.Desc);
                    break;
                }
                case "unTaxTotalAmount_desc": {
                    orderMap.put("unTaxTotalAmount", SortOrder.Desc);
                    break;
                }
                case "offsetTotal_desc": {
                    orderMap.put("offsetTotal", SortOrder.Desc);
                    break;
                }
                case "valueAddedTaxSubtotal_desc": {
                    orderMap.put("valueAddedTaxSubtotal", SortOrder.Desc);
                    break;
                }
                default:
                    orderMap.put("totalAmount", SortOrder.Desc);
                    break;
            }
        }
        orderList.add(orderMap);

        TermsAggregation termsAggregation = new TermsAggregation.Builder().field("companyId.keyword")
                .order(orderList).size((int)to).build();
        //数据聚合
        Aggregation aggregation = new Aggregation.Builder().terms(termsAggregation)
                .aggregations("totalAmount", EsUtil.sumAggregation("totalAmount"))
                .aggregations("taxTotalAmount", EsUtil.sumAggregation("taxTotalAmount"))
                .aggregations("unTaxTotalAmount", EsUtil.sumAggregation("unTaxTotalAmount"))
                .aggregations("offsetTotal", EsUtil.sumAggregation("offsetTotal"))
                .aggregations("valueAddedTaxSubtotal", EsUtil.sumAggregation("valueAddedTaxSubtotal"))
                .aggregations("commonValueAddedTax", EsUtil.sumAggregation("commonValueAddedTax"))
                .aggregations("offsetValueAddedTax", EsUtil.sumAggregation("offsetValueAddedTax"))
                .aggregations("exportRefundTax", EsUtil.sumAggregation("exportRefundTax"))
                .aggregations("changeValueAddedTax", EsUtil.sumAggregation("changeValueAddedTax"))
                .aggregations("consumeTax", EsUtil.sumAggregation("consumeTax"))
                .aggregations("businessTax", EsUtil.sumAggregation("businessTax"))
                .aggregations("financialBusinessTax", EsUtil.sumAggregation("financialBusinessTax"))
                .aggregations("companyIncomeTax", EsUtil.sumAggregation("companyIncomeTax"))
                .aggregations("personIncomeTax", EsUtil.sumAggregation("personIncomeTax"))
                .aggregations("resourceTax", EsUtil.sumAggregation("resourceTax"))
                .aggregations("cityConstructTax", EsUtil.sumAggregation("cityConstructTax"))
                .aggregations("houseTax", EsUtil.sumAggregation("houseTax"))
                .aggregations("stampTax", EsUtil.sumAggregation("stampTax"))
                .aggregations("urbanLandUseTax", EsUtil.sumAggregation("urbanLandUseTax"))
                .aggregations("landValueAddedTax", EsUtil.sumAggregation("landValueAddedTax"))
                .aggregations("carBoatTax", EsUtil.sumAggregation("carBoatTax"))
                .aggregations("farmlandUsedTax", EsUtil.sumAggregation("farmlandUsedTax"))
                .aggregations("deedTax", EsUtil.sumAggregation("deedTax"))
                .aggregations("otherTaxIncome", EsUtil.sumAggregation("otherTaxIncome"))
                .aggregations("educationSurchargeIncome", EsUtil.sumAggregation("educationSurchargeIncome"))
                .aggregations("localEducationSurchargeIncome", EsUtil.sumAggregation("localEducationSurchargeIncome"))
                .aggregations("culturalConstructionFee", EsUtil.sumAggregation("culturalConstructionFee"))
                .aggregations("localWaterConstructionIncome", EsUtil.sumAggregation("localWaterConstructionIncome"))
                .aggregations("deformitySecurityIncome", EsUtil.sumAggregation("deformitySecurityIncome"))
//                .aggregations("environmentalProtectionTax", EsUtil.sumAggregation("environmentalProtectionTax"))
                .aggregations("companyInfo", EsUtil.topHitsAggregation((int) 1))
                .aggregations("taxYear", EsUtil.maxAggregation("taxYear"))
                .build();


        //聚合统计
        String aggregationName = "taxPayment";
        SearchResponse<CompanyTax> search = esClient.search(builder -> builder
                        .index("financial_index_company_tax")
                        .size(0)
                        .query(taxPaymentQuery)
                        .aggregations(aggregationName, aggregation)
                , CompanyTax.class);

        List<TaxPaymentDataVo> res = new ArrayList<>();
        Aggregate companyTaxAggregate = search.aggregations().get(aggregationName);
        List<StringTermsBucket> bucketList = companyTaxAggregate.sterms().buckets().array();
        for (int i = (int)from; i < (int)to; i++) {
            StringTermsBucket bucket = bucketList.get(i);
            //todo 年份处理
//            Integer taxYear = Integer.parseInt(taxBucket.key().split("_")[1]);
            Map<String, Aggregate> aggregationMap = bucket.aggregations().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            TaxPaymentDataVo tmp = new TaxPaymentDataVo(null, aggregationMap, searchObject.getAmountUnit() != null && "W_YUAN".equals(searchObject.getAmountUnit()), false);
            res.add(tmp);
        }

        PageInfo<TaxPaymentDataVo> pageInfo = new PageInfo<>(res);
        ResponsePageDto<TaxPaymentDataVo> responsePageDto = PageUtil.getResponsePageDto(pageInfo);
        responsePageDto.setTotal(total);
        responsePageDto.setFirst(paramsDto.getCurrent() == 1);
        responsePageDto.setIsLast(to == total);
        return responsePageDto;
    }

    private static TaxPaymentDataVo queryTaxPaymentTotal(ElasticsearchClient esClient, TaxPaymentSearchObjectDto searchObject) throws Exception {
        Query taxPaymentQuery = getTaxPaymentQuery(searchObject);

        //聚合统计
        String aggregationName = "taxPayment";
        SearchResponse<CompanyTax> search = esClient.search(builder -> builder
                        .index("financial_index_company_tax")
                        .size(0)
                        .query(taxPaymentQuery)
                        .aggregations("totalAmount", EsUtil.sumAggregation("totalAmount"))
                        .aggregations("taxTotalAmount", EsUtil.sumAggregation("taxTotalAmount"))
                        .aggregations("unTaxTotalAmount", EsUtil.sumAggregation("unTaxTotalAmount"))
                        .aggregations("offsetTotal", EsUtil.sumAggregation("offsetTotal"))
                        .aggregations("valueAddedTaxSubtotal", EsUtil.sumAggregation("valueAddedTaxSubtotal"))
                        .aggregations("commonValueAddedTax", EsUtil.sumAggregation("commonValueAddedTax"))
                        .aggregations("offsetValueAddedTax", EsUtil.sumAggregation("offsetValueAddedTax"))
                        .aggregations("exportRefundTax", EsUtil.sumAggregation("exportRefundTax"))
                        .aggregations("changeValueAddedTax", EsUtil.sumAggregation("changeValueAddedTax"))
                        .aggregations("consumeTax", EsUtil.sumAggregation("consumeTax"))
                        .aggregations("businessTax", EsUtil.sumAggregation("businessTax"))
                        .aggregations("financialBusinessTax", EsUtil.sumAggregation("financialBusinessTax"))
                        .aggregations("companyIncomeTax", EsUtil.sumAggregation("companyIncomeTax"))
                        .aggregations("personIncomeTax", EsUtil.sumAggregation("personIncomeTax"))
                        .aggregations("resourceTax", EsUtil.sumAggregation("resourceTax"))
                        .aggregations("cityConstructTax", EsUtil.sumAggregation("cityConstructTax"))
                        .aggregations("houseTax", EsUtil.sumAggregation("houseTax"))
                        .aggregations("stampTax", EsUtil.sumAggregation("stampTax"))
                        .aggregations("urbanLandUseTax", EsUtil.sumAggregation("urbanLandUseTax"))
                        .aggregations("landValueAddedTax", EsUtil.sumAggregation("landValueAddedTax"))
                        .aggregations("carBoatTax", EsUtil.sumAggregation("carBoatTax"))
                        .aggregations("farmlandUsedTax", EsUtil.sumAggregation("farmlandUsedTax"))
                        .aggregations("deedTax", EsUtil.sumAggregation("deedTax"))
                        .aggregations("otherTaxIncome", EsUtil.sumAggregation("otherTaxIncome"))
                        .aggregations("educationSurchargeIncome", EsUtil.sumAggregation("educationSurchargeIncome"))
                        .aggregations("localEducationSurchargeIncome", EsUtil.sumAggregation("localEducationSurchargeIncome"))
                        .aggregations("culturalConstructionFee", EsUtil.sumAggregation("culturalConstructionFee"))
                        .aggregations("localWaterConstructionIncome", EsUtil.sumAggregation("localWaterConstructionIncome"))
                        .aggregations("deformitySecurityIncome", EsUtil.sumAggregation("deformitySecurityIncome"))
//                .aggregations("environmentalProtectionTax", EsUtil.sumAggregation("environmentalProtectionTax"))
                , CompanyTax.class);

        Map<String, Aggregate> aggregationMap = search.aggregations();
        return new TaxPaymentDataVo(null, aggregationMap, searchObject.getAmountUnit() != null && "W_YUAN".equals(searchObject.getAmountUnit()), true);
    }

    /**
     * 根据税务查询数据获取查询条件
     *
     * @param searchObject 查询条件
     * @return 查询条件
     */
    private static Query getTaxPaymentQuery(TaxPaymentSearchObjectDto searchObject) {
        //查询条件封装
        List<Query> queryList = new ArrayList<>();
        //企业模糊查找
        if (StringUtils.isNotBlank(searchObject.getCompanyName())) {
            if (searchObject.getCompanyName().contains("*")) {
                searchObject.setCompanyName(searchObject.getCompanyName().replace("*", "\\*"));
            }
            queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*" + searchObject.getCompanyName() + "*"));
        }
        //纳税人识别号查找
        if (StringUtils.isNotBlank(searchObject.getTaxpayersCreditCode())) {
            queryList.add(EsUtil.termQuery("taxpayersCreditCode", searchObject.getTaxpayersCreditCode()));
        }
        //集团匹配
        if (!CollectionUtils.isEmpty(searchObject.getGroupIds())) {
            queryList.add(EsUtil.matchQuery("groupId", String.join(",", searchObject.getGroupIds())));
        }
        //财政行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getFinanceIndustryCodes())) {
            queryList.add(EsUtil.matchQuery("financeIndustryId", String.join(",", searchObject.getFinanceIndustryCodes())));
        }
        //财政行业匹配
        if (!CollectionUtils.isEmpty(searchObject.getFinancePartCodes())) {
            queryList.add(EsUtil.matchQuery("financePartId", String.join(",", searchObject.getFinancePartCodes())));
        }
        //工商行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getBusinessIndustryCodes())) {
            queryList.add(EsUtil.matchQuery("businessIndustryId", String.join(",", searchObject.getBusinessIndustryCodes())));
        }
        //税务行业逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getTaxIndustryCodes())) {
            queryList.add(EsUtil.matchQuery("taxIndustryId", String.join(",", searchObject.getTaxIndustryCodes())));
        }
        //企业属性逐个匹配
        if (!CollectionUtils.isEmpty(searchObject.getCompanyAttributeCodes())) {
            queryList.add(EsUtil.matchQuery("attributeId", String.join(",", searchObject.getCompanyAttributeCodes())));
        }
        //金额类型
        if (StringUtils.isNotBlank(searchObject.getAmountType()) && searchObject.getAmountMax() != null && searchObject.getAmountMin() != null) {
            queryList.add(EsUtil.rangeQuery(searchObject.getAmountType(), searchObject.getAmountMax(), true, searchObject.getAmountMin(), true));
        }
        //月份
        if (searchObject.getTaxMonthMin() != null && searchObject.getTaxMonthMax() != null) {
            queryList.add(EsUtil.rangeQuery("taxMonth", searchObject.getTaxMonthMin(), true, searchObject.getTaxMonthMax(), true));
        }
        //年份
        if (searchObject.getTaxYear() != null) {
            queryList.add(EsUtil.termQuery("taxYear", String.valueOf(searchObject.getTaxYear())));
        }
        //成立日期
        if (searchObject.getEstablishStartDate() != null && searchObject.getEstablishEndDate() != null) {
            queryList.add(EsUtil.rangeQuery("establishDate", searchObject.getEstablishStartDate(), true, searchObject.getEstablishEndDate(), true));
        }

        //查询条件统计
        List<Query> mustNotList = new ArrayList<>();
        mustNotList.add(EsUtil.termQuery("taxYear", "-1"));
        BoolQuery boolQuery = new BoolQuery.Builder().must(queryList).mustNot(mustNotList).build();
        return new Query.Builder().bool(boolQuery).build();
    }

    private static void createCompany(ElasticsearchClient esClient, Company company) throws Exception {
        esClient.index(idx -> idx.index("company").id(company.getCompanyId()).document(company));
    }

    private static void delete(ElasticsearchClient esClient, String key) throws Exception {
        esClient.delete(builder -> builder.index("company").id(key));
    }

    private static void updateByQuery(ElasticsearchClient esClient, JsonData jsonData) throws Exception {
        Query query = EsUtil.termQuery("companyId", "bcscb");
//        InlineScript inlineScript = new InlineScript.Builder().source("ctx._source.companyName = 'hhhhh1'").build();
        InlineScript inlineScript = new InlineScript.Builder().source("ctx._source = params.newDoc").params("newDoc", jsonData).build();
        Script script = new Script.Builder().inline(inlineScript).build();
        UpdateByQueryResponse company = esClient.updateByQuery(builder -> builder.index("company").script(script).query(query));
        System.out.println("11111");
    }

    private static void test3(ElasticsearchClient esClient) throws IOException {
        SearchResponse<Company> search = esClient.search(builder -> builder
                        .index("company")
                , Company.class);
        List<Company> collect = search.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
        for (Company company : collect) {
            System.out.println(company.getCompanyName() + " " + JsonUtil.toJSONString(company.getFinancePartId()));
        }
    }

    private static void test2(ElasticsearchClient esClient) throws IOException {
        //        esClient.indices().create(c -> c.index("company"));
        Company company = new Company();
        Map<String, String> map = new HashMap<>();
        map.put("2024", "xxx");
        map.put("2023", "aaa");
        company.setCompanyName("合并22");
        company.setEstablishDate(new Date());
        company.setFinancePartId(map);

        esClient.index(idx -> idx
                .index("company2")
                .id(IdGenerator.getNextId())
                .document(company));
    }

    private static void test1(ElasticsearchClient esClient) throws IOException {
        List<Query> queryList = new ArrayList<>();
        queryList.add(EsUtil.wildcardQuery("companyName.keyword", "*汽车销售有限公司*"));
//        queryList.add(EsUtil.wildcardQuery("taxpayersCreditCode.keyword", "*2330205*"));
//        queryList.add(EsUtil.termQuery("totalAmount", "3260.25"));
//        queryList.add(EsUtil.rangeQuery("totalAmount", "3260.25", true, "3260.27", false));

        BoolQuery boolQuery = new BoolQuery.Builder().must(queryList).build();
        Query queryBool = new Query.Builder().bool(boolQuery).build();

        Map<String, Aggregation> map = new HashMap<>();
        map.put("totalAmount", sumAggregation("totalAmount"));
        map.put("valueAddedTaxSubtotal", sumAggregation("valueAddedTaxSubtotal"));
//        map.put("companyName.keyword", sumAggregation("companyName.keyword"));

        SearchResponse<CompanyTax> search = esClient.search(builder -> builder
                .index("company_tax")
//                .query(EsUtil.wildcardQuery("companyName.keyword", "*公司*"))
//                .from(0)
//                .size(5)
                .aggregations("totalAmountSum", builder1 -> builder1.terms(builder2 -> builder2.field("companyName.keyword")).aggregations("suma", builder3 -> builder3.sum(new SumAggregation.Builder().field("totalAmount").build())))
//                .aggregations("totalAmountSum", EsUtil.termsMapAggregation("companyName.keyword", map))
//                .aggregations("totalAmountSum", termsAggregation("companyName.keyword"))
                .sort(EsUtil.sortOptions("totalAmount", false)), CompanyTax.class);

        System.out.println(search.toString());

        List<CompanyTax> collect = search.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
        for (CompanyTax companyTax : collect) {
            System.out.println(companyTax.getCompanyName() + " " + companyTax.getTotalAmount() + " " + companyTax.getValueAddedTaxSubtotal());
        }
        Aggregate totalAmountSum = search.aggregations().get("totalAmountSum");
        List<StringTermsBucket> array = totalAmountSum.sterms().buckets().array();
        List<Map<String, Double>> maps = array.stream().map(stringTermsBucket -> stringTermsBucket.aggregations().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, stringAggregateEntry -> stringAggregateEntry.getValue().sum().value()))).collect(Collectors.toList());
        System.out.println(maps);

//        System.out.println(JsonUtil.toJSONString(collect));
        // select totalAmount as ta , subAmount as sa from company_tax group by companyId order by ta
    }

    private static void testCompanyCreate(ElasticsearchClient esClient) throws IOException {
        Map<String, Property> propertyMap = new HashMap<>();
        Map<String, Property> yearPropertyMap = new HashMap<>();

        PatternAnalyzer patternAnalyzer = new PatternAnalyzer.Builder().pattern(",").build();
        Analyzer analyzer = new Analyzer.Builder().pattern(patternAnalyzer).build();
        IndexSettingsAnalysis douHao = new IndexSettingsAnalysis.Builder().analyzer("dou_hao", analyzer).build();
        IndexSettings indexSettings = new IndexSettings.Builder().analysis(douHao).build();

        Property keywordProperty = Property.of(builder -> builder.keyword(b -> b));
        Property douHaoProperty = Property.of(builder -> builder.text(b -> b.fields("keyword", keywordProperty).analyzer("dou_hao").searchAnalyzer("dou_hao")));
        Property textProperty = Property.of(builder -> builder.text(b -> b.fields("keyword", keywordProperty)));
        Property dateProperty = Property.of(builder -> builder.date(b -> b));
        Property intProperty = Property.of(builder -> builder.integer(b -> b));
        Property pointProperty = Property.of(builder -> builder.scaledFloat(b -> b.scalingFactor(100.0)));
        yearPropertyMap.put(String.valueOf(Year.now().getValue()), douHaoProperty);
        Property mapProperty = Property.of(builder -> builder.object(b -> b.properties(yearPropertyMap)));

        propertyMap.put("id", textProperty);
        propertyMap.put("gmtCreate", dateProperty);
        propertyMap.put("nameCreate", textProperty);
        propertyMap.put("gmtModified", dateProperty);
        propertyMap.put("nameModified", textProperty);
        propertyMap.put("isDeleted", intProperty);
        propertyMap.put("companyId", textProperty);
        propertyMap.put("companyName", textProperty);
        propertyMap.put("taxpayersCreditCode", textProperty);
        propertyMap.put("legalPersonName", textProperty);
        propertyMap.put("legalPersonTel", textProperty);
        propertyMap.put("contactPersonName", textProperty);
        propertyMap.put("contactPersonTel", textProperty);
        propertyMap.put("financeIndustryId", douHaoProperty);
        propertyMap.put("financeIndustryName", douHaoProperty);
        propertyMap.put("financePartId", mapProperty);
        propertyMap.put("financePartName", mapProperty);
        propertyMap.put("businessIndustryId", douHaoProperty);
        propertyMap.put("businessIndustryName", douHaoProperty);
        propertyMap.put("taxIndustryId", douHaoProperty);
        propertyMap.put("taxIndustryName", douHaoProperty);
        propertyMap.put("establishDate", dateProperty);
        propertyMap.put("registerDepartment", textProperty);
        propertyMap.put("companyTypeId", douHaoProperty);
        propertyMap.put("companyType", douHaoProperty);
        propertyMap.put("groupId", douHaoProperty);
        propertyMap.put("groupName", douHaoProperty);
        propertyMap.put("attributeId", douHaoProperty);
        propertyMap.put("attributeName", douHaoProperty);
        propertyMap.put("registerCapital", textProperty);
        propertyMap.put("operatingAddress", textProperty);
        propertyMap.put("manageDepartment", textProperty);
        propertyMap.put("operatingRange", textProperty);

        Map<String, DynamicTemplate> dynamicTemplateMap = new HashMap<>();
        DynamicTemplate dynamicTemplate = new DynamicTemplate.Builder().matchMappingType("double").mapping(pointProperty).build();
        dynamicTemplateMap.put("my_point_number", dynamicTemplate);

        esClient.indices().create(c -> c.index("test_company1").settings(indexSettings).mappings(builder -> builder.properties(propertyMap)
                .dynamicTemplates(dynamicTemplateMap)));
    }

    private static void testTaxPaymentCreate(ElasticsearchClient esClient) throws IOException {
        Map<String, Property> propertyMap = new HashMap<>();

        PatternAnalyzer patternAnalyzer = new PatternAnalyzer.Builder().pattern(",").build();
        Analyzer analyzer = new Analyzer.Builder().pattern(patternAnalyzer).build();
        IndexSettingsAnalysis douHao = new IndexSettingsAnalysis.Builder().analyzer("dou_hao", analyzer).build();
        IndexSettings indexSettings = new IndexSettings.Builder().analysis(douHao).build();

        Property keywordProperty = Property.of(builder -> builder.keyword(b -> b));
        Property douHaoProperty = Property.of(builder -> builder.text(b -> b.fields("keyword", keywordProperty).analyzer("dou_hao").searchAnalyzer("dou_hao")));
        Property textProperty = Property.of(builder -> builder.text(b -> b.fields("keyword", keywordProperty)));
        Property dateProperty = Property.of(builder -> builder.date(b -> b));
        Property intProperty = Property.of(builder -> builder.integer(b -> b));
        Property pointProperty = Property.of(builder -> builder.scaledFloat(b -> b.scalingFactor(100.0).nullValue(0.0)));

        propertyMap.put("taxYearCompanyId", textProperty);
        propertyMap.put("companyId", textProperty);
        propertyMap.put("companyName", textProperty);
        propertyMap.put("taxpayersCreditCode", textProperty);
        propertyMap.put("legalPersonName", textProperty);
        propertyMap.put("legalPersonTel", textProperty);
        propertyMap.put("contactPersonName", textProperty);
        propertyMap.put("contactPersonTel", textProperty);
        propertyMap.put("financeIndustryId", douHaoProperty);
        propertyMap.put("financeIndustryName", douHaoProperty);
        propertyMap.put("financePartId", douHaoProperty);
        propertyMap.put("financePartName", douHaoProperty);
        propertyMap.put("businessIndustryId", douHaoProperty);
        propertyMap.put("businessIndustryName", douHaoProperty);
        propertyMap.put("taxIndustryId", douHaoProperty);
        propertyMap.put("taxIndustryName", douHaoProperty);
        propertyMap.put("establishDate", dateProperty);
        propertyMap.put("registerDepartment", textProperty);
        propertyMap.put("companyTypeId", douHaoProperty);
        propertyMap.put("companyType", douHaoProperty);
        propertyMap.put("groupId", douHaoProperty);
        propertyMap.put("groupName", douHaoProperty);
        propertyMap.put("attributeId", douHaoProperty);
        propertyMap.put("attributeName", douHaoProperty);
        propertyMap.put("registerCapital", textProperty);
        propertyMap.put("operatingAddress", textProperty);
        propertyMap.put("manageDepartment", textProperty);
        propertyMap.put("operatingRange", textProperty);
        propertyMap.put("taxYear", intProperty);
        propertyMap.put("taxMonth", intProperty);
        propertyMap.put("totalAmount", pointProperty);
        propertyMap.put("taxTotalAmount", pointProperty);
        propertyMap.put("unTaxTotalAmount", pointProperty);
        propertyMap.put("offsetTotal", pointProperty);
        propertyMap.put("valueAddedTaxSubtotal", pointProperty);
        propertyMap.put("commonValueAddedTax", pointProperty);
        propertyMap.put("offsetValueAddedTax", pointProperty);
        propertyMap.put("exportRefundTax", pointProperty);
        propertyMap.put("changeValueAddedTax", pointProperty);
        propertyMap.put("consumeTax", pointProperty);
        propertyMap.put("businessTax", pointProperty);
        propertyMap.put("financialBusinessTax", pointProperty);
        propertyMap.put("companyIncomeTax", pointProperty);
        propertyMap.put("personIncomeTax", pointProperty);
        propertyMap.put("resourceTax", pointProperty);
        propertyMap.put("cityConstructTax", pointProperty);
        propertyMap.put("houseTax", pointProperty);
        propertyMap.put("stampTax", pointProperty);
        propertyMap.put("urbanLandUseTax", pointProperty);
        propertyMap.put("landValueAddedTax", pointProperty);
        propertyMap.put("carBoatTax", pointProperty);
        propertyMap.put("farmlandUsedTax", pointProperty);
        propertyMap.put("deedTax", pointProperty);
        propertyMap.put("otherTaxIncome", pointProperty);
        propertyMap.put("educationSurchargeIncome", pointProperty);
        propertyMap.put("localEducationSurchargeIncome", pointProperty);
        propertyMap.put("culturalConstructionFee", pointProperty);
        propertyMap.put("localWaterConstructionIncome", pointProperty);
        propertyMap.put("deformitySecurityIncome", pointProperty);
        propertyMap.put("environmentalProtectionTax", pointProperty);
        propertyMap.put("taxPaymentId", textProperty);

        Map<String, DynamicTemplate> dynamicTemplateMap = new HashMap<>();
        DynamicTemplate dynamicTemplate = new DynamicTemplate.Builder().matchMappingType("double").mapping(pointProperty).build();
        dynamicTemplateMap.put("my_point_number", dynamicTemplate);

        esClient.indices().create(c -> c.index("test_company_tax").settings(indexSettings).mappings(builder -> builder.properties(propertyMap)
                .dynamicTemplates(dynamicTemplateMap)));
    }
}
